package com.beanbean.record;

import android.content.Context;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class AudioRecorder {
    private final static String TAG = "AudioRecorder";
    private Context mContext;
    //音频输入-麦克风
    private final static int AUDIO_INPUT = MediaRecorder.AudioSource.MIC;
    //采用频率
    //44100是目前的标准，但是某些设备仍然支持22050，16000，11025
    //采样频率一般共分为22.05KHz、44.1KHz、48KHz三个等级
    private final static int AUDIO_SAMPLE_RATE = 44100;
    //声道 单声道
    private final static int AUDIO_CHANNEL = AudioFormat.CHANNEL_IN_MONO;
    //编码
    private final static int AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;
    // 缓冲区字节大小
    private int bufferSizeInBytes = 0;

    //录音对象
    private AudioRecord audioRecord;

    //录音状态
    private Status status = Status.IDLE;

    //文件名
    private File resultFile;

    //录音文件
    private List<String> filesList = new ArrayList<>();

    //线程池
    private ExecutorService mExecutorService;

    //录音监听
    private RecordStreamListener listener;


    public AudioRecorder(Context context) {
        mContext = context;
        mExecutorService = Executors.newCachedThreadPool();
    }

    /**
     * 创建录音对象
     */
    public void createAudio(String fileName, int audioSource, int sampleRateInHz, int channelConfig, int audioFormat) {
        // 获得缓冲区字节大小
        bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz,
                channelConfig, channelConfig);
        audioRecord = new AudioRecord(audioSource, sampleRateInHz, channelConfig, audioFormat, bufferSizeInBytes);
        this.resultFile = FileUtil.createFile(fileName);
    }

    /**
     * 创建默认的录音对象
     *
     * @param fileName 文件名
     */
    public void createDefaultAudio(String fileName) {
        // 获得缓冲区字节大小
        bufferSizeInBytes = AudioRecord.getMinBufferSize(AUDIO_SAMPLE_RATE,
                AUDIO_CHANNEL, AUDIO_ENCODING);
        audioRecord = new AudioRecord(AUDIO_INPUT, AUDIO_SAMPLE_RATE, AUDIO_CHANNEL, AUDIO_ENCODING, bufferSizeInBytes);
        this.resultFile = FileUtil.createFile(fileName);
        status = Status.READY;
        Log.i(TAG, "createDefaultAudio: bufferSizeInBytes=" + bufferSizeInBytes);
    }


    /**
     * 开始录音
     */
    public void startRecord() {
        if (status == Status.IDLE || audioRecord == null) {
            Log.e(TAG, "录音尚未初始化,请检查是否禁止了录音权限~");
            return;
        }
        if (status == Status.START) {
            Log.e(TAG, "正在录音~");
            return;
        }
        Log.d(TAG, "===startRecord===");
        String currentFileName = "bean_" + System.currentTimeMillis() + ".pcm";
        final String finalFileName = currentFileName;
        //将录音状态设置成正在录音状态
        status = Status.START;
        //使用线程池管理线程
        mExecutorService.execute(new Runnable() {
            @Override
            public void run() {
                writeDataTOFile(finalFileName);
            }
        });
    }


    /**
     * 停止录音
     */
    public void stopRecord() {
        Log.d(TAG, "===stopRecord===");
        if (status == Status.IDLE || status == Status.READY) {
            Log.e(TAG, "录音尚未开始~");
        } else {
            status = Status.STOP;
        }
    }

    /**
     * 取消录音
     */
    public void release() {
        filesList.clear();
        if (audioRecord != null) {
            audioRecord.release();
            audioRecord = null;
        }
        status = Status.IDLE;
    }


    /**
     * 将音频信息写入文件
     */
    private void writeDataTOFile(String currentFileName) {
        // new一个byte数组用来存一些字节数据，大小为缓冲区大小
        FileOutputStream fos = null;
        int readSize = 0;
        byte[] audioData = new byte[bufferSizeInBytes];
        try {
            File file = FileUtil.createFile(currentFileName);
            fos = new FileOutputStream(file);// 建立一个可存取字节的文件
            if (status == Status.START) {
                audioRecord.startRecording();
            }
            Log.i(TAG, "recording ...");
            while (status == Status.START) {
                readSize = audioRecord.read(audioData, 0, audioData.length);
                if (AudioRecord.ERROR_INVALID_OPERATION != readSize && fos != null) {
                    try {
                        fos.write(audioData, 0, readSize);
                        fos.flush();
                        if (listener != null) {
                            listener.onRecording(audioData, 0, audioData.length);
                        }
                    } catch (IOException e) {
                        Log.e(TAG, e.getMessage());
                    }
                }
            }
            audioRecord.stop();
            Log.i(TAG, "finish record ...");
            filesList.add(currentFileName);
            if (status == Status.STOP) {
                mergeFile();
            }
            if (listener != null) {
                listener.finishRecord();
            }
        } catch (IllegalStateException e) {
            Log.e(TAG, e.getMessage());
        } catch (FileNotFoundException e) {
            Log.e(TAG, e.getMessage());
        } finally {
            if (fos != null) {
                try {
                    fos.close();// 关闭写入流
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 释放资源
     */
    private void mergeFile() {
        Log.d(TAG, "===release===");
        try {
            if (filesList.size() > 0) {
                List<File> filePaths = new ArrayList<>();
                for (String file : filesList) {
                    filePaths.add(FileUtil.createFile(file));
                }
                //清除
                filesList.clear();
                //将多个pcm文件转化为wav文件
                mergePcmFiles(resultFile, filePaths);
                makeWav(1);
            }
        } catch (IllegalStateException e) {
            throw new IllegalStateException(e.getMessage());
        }
    }

    /**
     * 合并多个pcm文件为一个pcm文件
     *
     * @param recordFile 输出文件
     * @param files      多个文件源
     * @return
     */
    private boolean mergePcmFiles(File recordFile, List<File> files) {
        if (recordFile == null || files == null || files.size() <= 0) {
            return false;
        }
        FileOutputStream fos = null;
        BufferedOutputStream outputStream = null;
        byte[] buffer = new byte[1024];
        try {
            fos = new FileOutputStream(recordFile);
            outputStream = new BufferedOutputStream(fos);
            for (int i = 0; i < files.size(); i++) {
                BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(files.get(i)));
                int readCount;
                while ((readCount = inputStream.read(buffer)) > 0) {
                    outputStream.write(buffer, 0, readCount);
                }
                inputStream.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        } finally {
            try {
                if (outputStream != null) {
                    outputStream.close();
                }
                if (fos != null) {
                    fos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        for (int i = 0; i < files.size(); i++) {
            files.get(i).delete();
        }
        files.clear();
        return true;
    }

    /**
     * 添加Wav头文件
     */
    private void makeWav(int time) {
        new Handler(Looper.getMainLooper()).post(new Runnable() {
            @Override
            public void run() {
                if (!FileUtil.isFile(resultFile) || resultFile.length() == 0) {
                    return;
                }
                byte[] header = WavUtils.generateWavFileHeader((int) resultFile.length(), AUDIO_SAMPLE_RATE, AUDIO_CHANNEL, AUDIO_ENCODING);
                boolean ss = WavUtils.writeHeader(resultFile, header);
                Log.i(TAG, "makeWav: " + resultFile.getAbsolutePath());
            }
        });


    }

    /**
     * 录音对象的状态
     */
    public enum Status {
        //未开始
        IDLE,
        //预备
        READY,
        //录音
        START,
        //暂停
        PAUSE,
        //停止
        STOP
    }

    /**
     * 获取录音对象的状态
     *
     * @return
     */
    public Status getStatus() {
        return status;
    }

    /**
     * 获取本次录音文件的个数
     *
     * @return
     */
    public int getPcmFilesCount() {
        return filesList.size();
    }

    public String getAudioPath() {
        return resultFile.getAbsolutePath();
    }

    public RecordStreamListener getListener() {
        return listener;
    }

    public void setListener(RecordStreamListener listener) {
        this.listener = listener;
    }
}
